package edu.pku.sei.modeler.uml.commands.sequence;

import java.util.Iterator;

import edu.pku.sei.modeler.model.core.MetaModel;
import edu.pku.sei.modeler.model.core.MetaModelElement;
import edu.pku.sei.modeler.model.uml.BasicInteractions.ExecutionSpecification;
import edu.pku.sei.modeler.model.uml.BasicInteractions.Interaction;
import edu.pku.sei.modeler.model.uml.BasicInteractions.Lifeline;
import edu.pku.sei.modeler.model.uml.BasicInteractions.Message;
import edu.pku.sei.modeler.model.uml.BasicInteractions.MessageOccurrenceSpecification;
import edu.pku.sei.modeler.uml.commands.ConnectionModelDeleteCommand;

public class UMLMessageDeleteCommand extends ConnectionModelDeleteCommand {

	private MessageOccurrenceSpecification startEventOccurrence;

	private MessageOccurrenceSpecification finishEventOccurrence;

	public UMLMessageDeleteCommand(MetaModelElement connectionModel,
			MetaModelElement sourceModel, MetaModelElement targetModel) {
		super(connectionModel, sourceModel, targetModel);
		
		if (this.sourceModel instanceof ExecutionSpecification && 
				this.targetModel instanceof ExecutionSpecification) {
			ExecutionSpecification sourceEO = (ExecutionSpecification) this.sourceModel;
			ExecutionSpecification targetEO = (ExecutionSpecification) this.targetModel;
			Message message = (Message) connectionModel;
			for (Iterator iter = sourceEO.getStart().iterator(); iter.hasNext();) {
				MessageOccurrenceSpecification element = (MessageOccurrenceSpecification) iter
						.next();
				if (element.getSendMessage() == message) {
					this.startEventOccurrence = element;
					break;
				}
			}
			for (Iterator iter = targetEO.getFinish().iterator(); iter.hasNext();) {
				MessageOccurrenceSpecification element = (MessageOccurrenceSpecification) iter
						.next();
				if (element.getReceiveMessage() == message) {
					this.finishEventOccurrence = element;
					break;
				}
			}
		} else if (this.sourceModel instanceof Lifeline && this.targetModel instanceof Lifeline) {
			Lifeline sourceEO = (Lifeline) this.sourceModel;
			Lifeline targetEO = (Lifeline) this.targetModel;
			Message message = (Message) connectionModel;
			for (Iterator iter = sourceEO.getStart().iterator(); iter.hasNext();) {
				MessageOccurrenceSpecification element = (MessageOccurrenceSpecification) iter
						.next();
				if (element.getSendMessage() == message) {
					this.startEventOccurrence = element;
					break;
				}
			}
			for (Iterator iter = targetEO.getFinish().iterator(); iter.hasNext();) {
				MessageOccurrenceSpecification element = (MessageOccurrenceSpecification) iter
						.next();
				if (element.getReceiveMessage() == message) {
					this.finishEventOccurrence = element;
					break;
				}
			}
		}
	}

	@Override
	public boolean canExecute() {
		boolean result = (this.targetModel instanceof ExecutionSpecification
				&& this.sourceModel instanceof ExecutionSpecification)
				|| (this.targetModel instanceof Lifeline
						&& this.sourceModel instanceof Lifeline);
		return result
				&& (this.sourceModel.getContainer().getContainer() instanceof Interaction);
	}

	@Override
	public void execute() {
		if (this.sourceModel instanceof ExecutionSpecification) {
			Interaction interaction = (Interaction) this.sourceModel.getContainer()
					.getContainer();
			Message message = (Message) this.connectionModel;
			interaction.getMessage().remove(message);
	
			ExecutionSpecification sourceEO = (ExecutionSpecification) this.sourceModel;
			ExecutionSpecification targetEO = (ExecutionSpecification) this.targetModel;
			sourceEO.getStart().remove(startEventOccurrence);
			targetEO.getFinish().remove(finishEventOccurrence);
		} else if (this.sourceModel instanceof Lifeline) {
			Interaction interaction = (Interaction) this.sourceModel.getContainer();
			Message message = (Message) this.connectionModel;
			interaction.getMessage().remove(message);
	
			Lifeline sourceEO = (Lifeline) this.sourceModel;
			Lifeline targetEO = (Lifeline) this.targetModel;
			sourceEO.getStart().remove(startEventOccurrence);
			targetEO.getFinish().remove(finishEventOccurrence);
		}
	}

	@Override
	public void undo() {
		if (this.sourceModel instanceof ExecutionSpecification) {
			Interaction interaction = (Interaction) this.sourceModel.getContainer()
					.getContainer();
			Message message = (Message) this.connectionModel;
			interaction.getMessage().add(message);
			MetaModel model = interaction.getModel();
			message.setModel(model);
			message.getMessageSort().setModel(model);
	
			ExecutionSpecification sourceEO = (ExecutionSpecification) this.sourceModel;
			ExecutionSpecification targetEO = (ExecutionSpecification) this.targetModel;
			sourceEO.getStart().add(startEventOccurrence);
			targetEO.getFinish().add(finishEventOccurrence);
		} else if (this.sourceModel instanceof Lifeline) {
			Interaction interaction = (Interaction) this.sourceModel.getContainer();
			Message message = (Message) this.connectionModel;
			interaction.getMessage().add(message);
			MetaModel model = interaction.getModel();
			message.setModel(model);
			message.getMessageSort().setModel(model);
	
			Lifeline sourceEO = (Lifeline) this.sourceModel;
			Lifeline targetEO = (Lifeline) this.targetModel;
			sourceEO.getStart().add(startEventOccurrence);
			targetEO.getFinish().add(finishEventOccurrence);
		}
	}
}
